#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <sys/wait.h>
#include "Task.hpp"

const int size = 256;

class Channel {
public:
    Channel(const std::string& name, pid_t subprocessid, size_t wfd)
        : _name(name)
        , _subprocessid(subprocessid)
        , _wfd(wfd)
    {} 

    pid_t GetSubProcessId() {
        return _subprocessid;
    }

    std::string GetSubName() {
        return _name;
    }

    size_t GetSubWfd() {
        return _wfd;
    }

    // 等待子进程退出
    void SubWait() {
        int status;
        pid_t rid = waitpid(_subprocessid, &status, 0);
        if (rid > 0)
            std::cout << _name << " wait success!" << " exit signal: " << (status & 0x7F) << std::endl;
        else
            std::cout << _name << " wait fail!" << " exit signal: " << (status & 0x7F) << std::endl;
    }

    // 关闭写端
    void CloseWfd() {
        close(_wfd);
        // std::cout << _name << " wfd close success!" << std::endl;
    }

private:
    std::string _name;
    pid_t _subprocessid;
    size_t _wfd;
};



void FatherCreateWorkerProcess(std::vector<Channel>* channels, int num) {
    for (int i = 0; i < num; i++) {
        int pipefd[2];
        int n = pipe(pipefd);
        if (n == -1) {
            std::cerr << "Create pipe fail! " << "error string: " << strerror(errno) << std::endl;
            exit(1);
        }
        // 使用fork创建出子进程
        // 创建出子进程之后，让子进程关闭掉写端，父进程关闭掉读端
        std::string name("worker-");
        name += std::to_string(i);

        pid_t id = fork();
        if (id == 0) {
            if (!channels->empty()) {
                for (auto& channel : *channels)
                    channel.CloseWfd();
            }
            close(pipefd[1]);
            // 子进程一直阻塞等待读入消息
            // 重定向子进程
            dup2(pipefd[0], 0);
            SubReadCommand(name);     
            close(pipefd[0]);       
            exit(0);    
        }
        close(pipefd[0]);
        Channel channel(name, id, pipefd[1]);
        channels->push_back(channel);
    }
}
    
size_t SelectSubProcess(int num) {
    static size_t cnt = 0;
    int ret = cnt;
    cnt++;
    cnt %= num;
    return ret;
}

void ControlProcessOnce(std::vector<Channel>& channels, int num) {
    int taskindex = SelectTask();
    // 然后让对应的子进程执行对应的程序
    size_t subindex = SelectSubProcess(num);
    write(channels[subindex].GetSubWfd(), &taskindex, sizeof(taskindex));
    std::cout << std::endl;
    sleep(1);
}

void ControlProcess(std::vector<Channel>& channels, int num, int times = -1) {
    // 让父进程向管道中输入信息
    // 先选中要执行的任务
    if (times > 0) 
        while (times--)
            ControlProcessOnce(channels, num);
    else
        while (true)
            ControlProcessOnce(channels, num);
}

void ClosePipeandSub(std::vector<Channel>& channels) {
    // 逐一关闭对应的，关闭了写端
    for (auto& channel : channels)
        channel.CloseWfd();
    for (auto& channel : channels)
        channel.SubWait();
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        std::cout << "the parameter of command line is not equal two, please input again" << std::endl;
        return 1;
    }
    // 加载任务
    LoadTask();
    // 创建子进程
    std::vector<Channel> channels;
    int channelnums = std::stoi(argv[1]);
    FatherCreateWorkerProcess(&channels, channelnums);

    // for (auto& channel : channels)
    //     std::cout << channel.GetSubName() << std::endl;

    // 控制子进程
    ControlProcess(channels, channelnums, -1);
    // 退出，关闭对饮的管道和子进程
    ClosePipeandSub(channels);
    return 0;
}